package frontend;

import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.RowFilter;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.TableRowSorter;

import model.LoanMasterCustomerTableModel;
import model.LoanMasterLoanTableModel;
import net.miginfocom.swing.MigLayout;
import domain.Customer;
import domain.Library;
import domain.Loan;

public class LoanMasterJPanel extends JPanel {
    private static final long serialVersionUID = -1761899999291798063L;
    private Library library;
    private JLabel lblOpenLoansValue;
    private JLabel lblTotalLoansValue;
    private JButton btnReturnLoan;
    private JTable tblLoans;
    private JTextField txtSearchLoan;
    private JCheckBox chckbxNurVerfgbare;
    private TableRowSorter<LoanMasterLoanTableModel> tblLoanSorter;
    private TableRowSorter<LoanMasterCustomerTableModel> tblCustomerSorter;
    private JLabel lblOverdueLoansValue;
    private JPanel pnlCustomer;
    private JTable tblCustomer;
    private JTextField txtSearchCustomer;
    private JButton btnCustomerDetails;
    private String loanTableCustomerFilter = "";
    private String loanTableUserFilter = "";
    private boolean loanTableOverdueFilter = false;
    ArrayList<RowFilter<Object, Object>> loanTableFilters = new ArrayList<RowFilter<Object, Object>>();

    /**
     * Create the frame.
     */
    public LoanMasterJPanel() {
        this.library = Library.getInstance();

        GridBagLayout gbl_masterPanel = new GridBagLayout();
        gbl_masterPanel.columnWidths = new int[] { 0, 0 };
        gbl_masterPanel.rowHeights = new int[] { 0, 0, 0, 0 };
        gbl_masterPanel.columnWeights = new double[] { 1.0, Double.MIN_VALUE };
        gbl_masterPanel.rowWeights = new double[] { 0.0, 50.0, 50.0, Double.MIN_VALUE };
        this.setLayout(gbl_masterPanel);

        JPanel pnlInventoryStats = new JPanel();
        pnlInventoryStats.setBorder(BorderFactory.createTitledBorder("Ausleih Statistiken"));
        GridBagConstraints gbc_pnlInventoryStats = new GridBagConstraints();
        gbc_pnlInventoryStats.insets = new Insets(5, 5, 5, 5);
        gbc_pnlInventoryStats.fill = GridBagConstraints.BOTH;
        gbc_pnlInventoryStats.gridx = 0;
        gbc_pnlInventoryStats.gridy = 0;
        this.add(pnlInventoryStats, gbc_pnlInventoryStats);
        pnlInventoryStats.setLayout(new MigLayout("", "[fill][fill][30px,fill][fill][fill][30px,fill][fill][fill]", "[]"));

        JLabel lblTotalLoans = new JLabel("Anzahl Ausleihen:");
        pnlInventoryStats.add(lblTotalLoans, "cell 0 0");

        lblTotalLoansValue = new JLabel("");
        pnlInventoryStats.add(lblTotalLoansValue, "cell 1 0");

        JLabel lblOpenLoans = new JLabel("Aktuell Ausgeliehen:");
        pnlInventoryStats.add(lblOpenLoans, "cell 3 0");

        lblOpenLoansValue = new JLabel("");
        pnlInventoryStats.add(lblOpenLoansValue, "cell 4 0");

        JLabel lblOverdueLoans = new JLabel("Überfällige Ausleihen:");
        pnlInventoryStats.add(lblOverdueLoans, "cell 6 0");

        lblOverdueLoansValue = new JLabel("");
        pnlInventoryStats.add(lblOverdueLoansValue, "cell 7 0");

        pnlCustomer = new JPanel();
        pnlCustomer.setBorder(BorderFactory.createTitledBorder("Kunden"));
        GridBagConstraints gbc_pnlCustomer = new GridBagConstraints();
        gbc_pnlCustomer.insets = new Insets(5, 5, 5, 5);
        gbc_pnlCustomer.fill = GridBagConstraints.BOTH;
        gbc_pnlCustomer.gridx = 0;
        gbc_pnlCustomer.gridy = 1;
        add(pnlCustomer, gbc_pnlCustomer);
        pnlCustomer.setLayout(new MigLayout("", "[300px:n][grow]", "[][grow][grow]"));

        txtSearchCustomer = new JTextField();
        txtSearchCustomer.setText("Suche");
        pnlCustomer.add(txtSearchCustomer, "cell 0 0,growx");
        txtSearchCustomer.setColumns(10);

        btnCustomerDetails = new JButton("Kunden Details");
        btnCustomerDetails.setEnabled(false);
        pnlCustomer.add(btnCustomerDetails, "cell 1 0,alignx right");

        tblCustomer = new JTable();
        tblCustomer.setModel(LoanMasterCustomerTableModel.getInstance());
        tblCustomer.getColumnModel().getColumn(3).setMinWidth(40);
        tblCustomer.getColumnModel().getColumn(3).setMaxWidth(40);
        // tblCustomer.getColumnModel().getColumn(1).setMinWidth(200);
        tblCustomerSorter = new TableRowSorter<LoanMasterCustomerTableModel>(LoanMasterCustomerTableModel.getInstance());
        tblCustomer.setRowSorter(tblCustomerSorter);
        pnlCustomer.add(new JScrollPane(tblCustomer), "cell 0 1 2 1,grow");

        JPanel pnlLoans = new JPanel();
        pnlLoans.setBorder(BorderFactory.createTitledBorder("Ausleihen"));
        GridBagConstraints gbc_pnlInvetory = new GridBagConstraints();
        gbc_pnlInvetory.insets = new Insets(5, 5, 5, 5);
        gbc_pnlInvetory.fill = GridBagConstraints.BOTH;
        gbc_pnlInvetory.gridx = 0;
        gbc_pnlInvetory.gridy = 2;
        this.add(pnlLoans, gbc_pnlInvetory);
        pnlLoans.setLayout(new MigLayout("", "[300px:n,fill][grow,fill][fill]", "[fill][grow,fill]"));

        txtSearchLoan = new JTextField();
        txtSearchLoan.setText("Suche");
        pnlLoans.add(txtSearchLoan, "cell 0 0,growx");
        txtSearchLoan.setColumns(10);

        chckbxNurVerfgbare = new JCheckBox("Nur Überfällige");
        pnlLoans.add(chckbxNurVerfgbare, "cell 1 0");

        btnReturnLoan = new JButton("Ausleihe zurückgeben");
        btnReturnLoan.setEnabled(false);
        pnlLoans.add(btnReturnLoan, "cell 2 0");

        tblLoans = new JTable();
        tblLoans.setModel(LoanMasterLoanTableModel.getInstance());
        tblLoans.getColumnModel().getColumn(0).setMinWidth(60);
        tblLoans.getColumnModel().getColumn(0).setMaxWidth(60);
        tblLoans.getColumnModel().getColumn(1).setMinWidth(40);
        tblLoans.getColumnModel().getColumn(1).setMaxWidth(40);
        tblLoans.getColumnModel().getColumn(2).setMinWidth(200);
        tblLoans.getColumnModel().getColumn(3).setMinWidth(170);
        tblLoans.getColumnModel().getColumn(3).setMaxWidth(170);
        tblLoanSorter = new TableRowSorter<LoanMasterLoanTableModel>(LoanMasterLoanTableModel.getInstance());
        tblLoans.setRowSorter(tblLoanSorter);
        pnlLoans.add(new JScrollPane(tblLoans), "cell 0 1 3 1,grow");

        attachActionListeners();
        updateFromLibrary();
        updateNumSelected();
    }

    private void updateLoansFilter() {
        loanTableFilters.clear();
        loanTableFilters.add(RowFilter.regexFilter(loanTableCustomerFilter, 4));

        try {
            loanTableFilters.add(RowFilter.regexFilter("(?i)" + loanTableUserFilter));
        } catch (Exception e) {
            System.out.println("Ungültiger Suchstring eingegeben.");
        }
        if (loanTableOverdueFilter) {
            loanTableFilters.add(RowFilter.regexFilter("fällig", 0));
        }
        tblLoanSorter.setRowFilter(RowFilter.andFilter(loanTableFilters));
    }

    private void attachActionListeners() {
        tblCustomer.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
            public void valueChanged(ListSelectionEvent e) {
                btnCustomerDetails.setEnabled(tblCustomer.getSelectedRowCount() > 0);
                if (tblCustomer.getSelectedColumnCount() > 0) {
                    loanTableCustomerFilter = "#";
                } else {
                    loanTableCustomerFilter = "";
                }
                for (int rowIndex : tblCustomer.getSelectedRows()) {
                    Customer cust = LoanMasterCustomerTableModel.getInstance().getElementAt(tblCustomer.convertRowIndexToModel(rowIndex));
                    loanTableCustomerFilter += "|" + cust.getSurname() + " " + cust.getName();
                }
                updateLoansFilter();
            }
        });
        tblLoans.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
            public void valueChanged(ListSelectionEvent e) {
                btnReturnLoan.setEnabled(tblLoans.getSelectedRowCount() > 0);
            }
        });
        txtSearchLoan.addKeyListener(new KeyAdapter() {
            @Override
            public void keyReleased(KeyEvent e) {
                loanTableUserFilter = txtSearchLoan.getText();
                updateLoansFilter();
            }
        });
        txtSearchCustomer.addKeyListener(new KeyAdapter() {
            @Override
            public void keyReleased(KeyEvent e) {
                try {
                    tblCustomerSorter.setRowFilter(RowFilter.regexFilter("(?i)" + txtSearchCustomer.getText()));
                } catch (Exception ex) {
                    System.out.println("Ungültiger Suchstring eingegeben.");
                }
            }
        });
        btnCustomerDetails.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                showSelectedCustomer();
            }
        });
        btnReturnLoan.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                while (tblLoans.getSelectedRow() >= 0) {
                    Loan loan = LoanMasterLoanTableModel.getInstance().getElementAt(tblLoans.convertRowIndexToModel(tblLoans.getSelectedRow()));
                    loan.returnCopy();
                }

            }
        });
        txtSearchLoan.addFocusListener(new FocusAdapter() {
            @Override
            public void focusGained(FocusEvent e) {
                if (txtSearchLoan.getText().equals("Suche")) {
                    txtSearchLoan.setText("");
                }
            }
        });
        txtSearchLoan.addFocusListener(new FocusAdapter() {
            @Override
            public void focusLost(FocusEvent e) {
                if (txtSearchLoan.getText().isEmpty()) {
                    txtSearchLoan.setText("Suche");
                }
            }
        });
        txtSearchCustomer.addFocusListener(new FocusAdapter() {
            @Override
            public void focusGained(FocusEvent e) {
                if (txtSearchCustomer.getText().equals("Suche")) {
                    txtSearchCustomer.setText("");
                }
            }
        });
        txtSearchCustomer.addFocusListener(new FocusAdapter() {
            @Override
            public void focusLost(FocusEvent e) {
                if (txtSearchCustomer.getText().isEmpty()) {
                    txtSearchCustomer.setText("Suche");
                }
            }
        });
        chckbxNurVerfgbare.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                if (chckbxNurVerfgbare.isSelected()) {
                    loanTableOverdueFilter = true;
                } else {
                    loanTableOverdueFilter = false;
                }
                updateLoansFilter();
            }
        });
        
        Action saveAction = new AbstractAction() {
            private static final long serialVersionUID = 1L;

            @Override
            public void actionPerformed(ActionEvent e) {
                showSelectedCustomer();
            }
        };
        
        tblCustomer.getInputMap().put(KeyStroke.getKeyStroke("ENTER"), "save");
        tblCustomer.getActionMap().put("save", saveAction);
        
        tblCustomer.addMouseListener(new MouseListener() {
            @Override
            public void mouseReleased(MouseEvent e) {
            }
            
            @Override
            public void mousePressed(MouseEvent e) {
            }
            
            @Override
            public void mouseExited(MouseEvent e) {
            }
            
            @Override
            public void mouseEntered(MouseEvent e) {
            }
            
            @Override
            public void mouseClicked(MouseEvent e) {
                if(e.getClickCount() >= 2) {
                    showSelectedCustomer();
                }
            }
        });
    }

    private void showSelectedCustomer() {
        Point location = LoanMasterJPanel.this.getLocation();
        for (int rowIndex : tblCustomer.getSelectedRows()) {
            Customer cust = LoanMasterCustomerTableModel.getInstance().getElementAt(tblCustomer.convertRowIndexToModel(rowIndex));
            if (CustomerDetailJFrame.hasInstance(cust)) {
                CustomerDetailJFrame.getInstance(cust).toFront();
            } else {
                CustomerDetailJFrame frame = CustomerDetailJFrame.getInstance(cust);
                if (java.awt.GraphicsEnvironment.getLocalGraphicsEnvironment().getMaximumWindowBounds().height < location.y + frame.getSize().height) {
                    location.y = 0;
                }
                frame.setLocation(location.x + 10, location.y + 22);
                location = frame.getLocation();
                frame.setVisible(true);
            }
        }
    }

    public void updateFromLibrary() {
        this.lblTotalLoansValue.setText(Integer.toString(library.getLoans().size()));
        this.lblOpenLoansValue.setText(Integer.toString(library.getOpenLoans().size()));
        this.lblOverdueLoansValue.setText(Integer.toString(library.getOverdueLoans().size()));
    }

    private void updateNumSelected() {}
}
